#include <memory>
#include <functional>
#include <iostream>
#include <vector>
#include <unordered_map>
#include <cstdint>

#include <unistd.h>

using TaskFunc = std::function<void()>; // 定时任务函数类型
using ReleaseFunc = std::function<void()>;
class TimerTask
{
private:
    uint64_t _id;         // 定时器任务对象ID
    uint32_t _timeout;    // 定时任务的超时时间
    bool _canceled;       // false表示未被取消，true表示被取消
    TaskFunc _task_cb;    // 定时器对象要执行的定时任务
    ReleaseFunc _release; // 用于删除TimerWheel中保存的定时器对象信息
public:
    TimerTask(uint64_t id, uint32_t delay /*延迟时间*/, const TaskFunc &cb)
        : _id(id), _timeout(delay), _task_cb(cb), _canceled(false) {}
    ~TimerTask()
    {
        if (_canceled == false)
            _task_cb();
        _release();
    }
    void Cancel()
    {
        _canceled = true;
    }
    void SetRelease(const ReleaseFunc &cb) { _release = cb; }
    uint32_t DelayTime() { return _timeout; };
};

class TimerWheel
{
private:
    using WeakTask = std::weak_ptr<TimerTask>;
    using PtrTask = std::shared_ptr<TimerTask>;
    int _tick;     // tick走到哪里就释放哪里的对象，释放哪里，就相当于执行哪里的任务
    int _capacity; // 表盘最大数量---其实就是最大延迟时间
    // 当我们要二次添加同一个定时器任务对象的时候，得能够找到他们的同一个计数器，使用weak_ptr辅助shared_ptr
    // 保存所有定时器的weak_ptr对象，因为只有保存了WeakTask才有可能通过WeakTask构造出新的shared_ptr，
    // 并且他们共享计数,并且WeakTask自身不影响计数
    std::vector<std::vector<PtrTask>> _wheel;
    std::unordered_map<uint64_t, WeakTask> _timers;

private:
    void RemoveTimerInfo(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it != _timers.end())
        {
            _timers.erase(it);
        }
    }

public:
    TimerWheel() : _capacity(60), _tick(0), _wheel(_capacity) {}
    // 添加定时任务
    void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cb)
    {
        PtrTask pt(new TimerTask(id, delay, cb));
        pt->SetRelease(std::bind(&TimerWheel::RemoveTimerInfo, this, id));
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);
        _timers[id] = WeakTask(pt);
    }
    // 刷新/延迟定时任务
    void TimerRefresh(uint64_t id)
    {
        // 通过保存的定时器对象的weak_ptr构造一个shared_ptr出来，添加到轮子中
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            // 没找到定时任务，没法刷新，没法延时
            return;
        }
        PtrTask pt = it->second.lock(); // lock获取weak_ptr所管理对象对应的的shared_ptr
        int delay = pt->DelayTime();
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);
    }
    // 取消一个定时任务
    void TimerCancel(uint64_t id)
    {
        // 通过保存的定时器对象的weak_ptr构造一个shared_ptr出来，添加到轮子中
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            // 没找到定时任务，没法刷新，没法延时
            return;
        }
        PtrTask pt = it->second.lock(); // lock获取weak_ptr所管理对象对应的的shared_ptr
        if (pt)
            pt->Cancel();
    }
    // 这个函数每秒钟执行一次，相当于秒针向后走了一步
    void RunTimerTask()
    {
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear(); // 清空指定位置的数组，就能将数组中保存的所有管理对象的shared_ptr释放掉
    }
};

// 测试类
//  通过释放过程来看任务执行情况
class Test
{
private:
public:
    Test() { std::cout << "构造" << std::endl; }
    ~Test() { std::cout << "析构" << std::endl; }
};

void DelTest(Test *t)
{
    delete t;
}

int main()
{
    TimerWheel tw;

    Test *t = new Test();
    tw.TimerAdd(8, 5, std::bind(DelTest, t));
    for (int i = 0; i < 5; i++)
    {
        // sleep(1);

        tw.TimerRefresh(8); // 刷新定时任务
        tw.RunTimerTask();  // 向后移动秒针
        printf("刷新了一下定时任务，重新需要5s才会被销毁\n");
    }
    // tw.TimerCancel(8);
    while (1)
    {
        std::cout << "-----------------------" << std::endl;
        sleep(1);
        tw.RunTimerTask(); // 向后移动指针
    }

    return 0;
}
